#pragma once
#include <DirectXMath.h>
#include <vector>
#include <string>

namespace mz {

struct Primitive{
	Primitive(float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2);

	bool operator < (const Primitive& p);

	DirectX::XMVECTOR vertices[3];
	DirectX::XMVECTOR normal;

	unsigned char r,g,b;

	float yMax, stride;
};

struct Edge{
	float cx, cz, dx, dz, ey;
};

struct EdgePair{
	Edge& operator[](int i){return data[i];}
	const Edge& operator[](int i)const{return data[i];}

	//prepare for the next scanline
	//@return need to update this prim?
	bool nextScanLine(float nextLine, float yStride){
		for(auto& edge : data){
			edge.cx += edge.dx * yStride;
			edge.cz += edge.dz * yStride;
			if(edge.ey > nextLine) return true;
		}
		return false;
	}
	
	const Primitive& GetParentPrim()const{
		return *prim;
	}

	void SetParentPrim(const Primitive* prim){
		this->prim = prim;
	}

private:
	Edge data[2];
	const Primitive* prim;
};

bool GetEdgePair(const Primitive& prim, const float curLine, EdgePair& pair);

struct SoftGPU{
	~SoftGPU();

	bool Init(const std::string& modelPath, const DirectX::XMMATRIX& matrix, int width, int height);
	unsigned char* Scan();
	void Free();

protected:
	void TransformAndClip();

	std::vector<Primitive> m_primitives;

	DirectX::XMMATRIX m_matrix;
	int m_width, m_height;

	float* m_zBuffer;
	unsigned char* m_cBuffer;

};

}